/*=====================================================================

  File:      StoreCustom.cs
  Summary:   SQL Remote Blob Storage sample application - StoreCustom.
             Sample application used to store blob data, 
             creating a new collection and specifying this collection.
  Date:      July 21st, 2008

---------------------------------------------------------------------

  This file is part of the Microsoft SQL Server Code Samples.
  Copyright (C) Microsoft Corporation.  All rights reserved.

This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation.  See these other
materials for detailed information regarding Microsoft code samples.

THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

======================================================= */

using System;
using System.Data.SqlClient;
using System.Text;
using System.Transactions;

using Microsoft.Data.SqlRemoteBlobs;

namespace Microsoft.Samples.RemoteBlobStorage
{
    /// <summary>
    /// Sample Remote Blob Storage Application.
    /// </summary>
    public
    sealed
    class StoreCustom
    {
        private StoreCustom() { }

        public
        static
        void RunStoreCustom(string connectionString)
        {
            Console.WriteLine("Running the Store Custom Sample");

            // Custom write blob. Creates a new collection and creates a new blob in the new collection.
            //
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();

                // Create a blob context to operate againt RBS.
                //
                SqlRemoteBlobContext blobContext = new SqlRemoteBlobContext(conn);

                int collectionId = 0;

                // Create a new collection. A collection is an application level logical container for a set of 
                // blobs. Most policy can be set and managed at a collection level, for instance which blob store
                // to use for storing blobs. A collection is also the unit of migration, for instance if an 
                // application wants to move blob data from one provider to another this must be done by migrating
                // the entire collection.
                //
                // This must be done in a seperate transaction and committed directly after the creation succeeds
                // to prevent locking issues.
                //
                using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
                {
                    conn.EnlistTransaction(Transaction.Current);

                    // Build configuration to specify the collection.
                    //
                    ConfigItemList configList = new ConfigItemList();

                    // OwningApplication is a useful way of keeping track of which applications create collections.
                    // It is not used by RBS internally to map application names to default collections.
                    // Collection IDs need to be stored and specified by the application when creating new blobs.
                    //
                    configList.OwningApplication = "RBS Test Application";

                    // If a default blob store is specified for this collection any blobs added to this collection
                    // will be placed into this blob store. This is an optional argument, if not specified the
                    // blobs will be placed into the RBS wide default blob store specified by executing 
                    // mssqlrbs.rbs_sp_set_config_value 'default_blob_store_name', '<blob store name>'
                    //
                    // configList.DefaultBlobStoreName = "FileStoreProvider_1";

                    // Create the new collection, passing in the configuration set.
                    //
                    SqlRemoteBlobCollectionManager collection = blobContext.CreateNewCollection(configList);

                    // Get the collection ID. The application should store this ID somewhere persistent to allow
                    // subsequent executions of the application to use the collection.
                    //
                    collectionId = collection.CollectionId;

                    // Commit the transaction wrapping CreateNewCollection.
                    //
                    ts.Complete();
                }

                // Create our blob, passing in the collection id to use.
                // Another overload of CreateNewBlob allows passing a specific blob store name in as a 
                // ConfigItemList object as above. This will override any default blob store information 
                // specified in either the machine wide configuration value or the collection default blob 
                // store.
                //
                using (SqlRemoteBlob blob = blobContext.CreateNewBlob(collectionId))
                {
                    // Store new blob data.
                    //
                    byte[] blobData = Encoding.Unicode.GetBytes("Remote Blob Storage Sample Application Store Custom Test Data");
                    blob.Write(blobData, 0, blobData.Length);

                    // Call commit to indicate we're done writing to the stream.
                    //
                    blob.Commit();

                    // Once all the data has been written to the blob, the next step is to register the blob 
                    // with the RBS auxiliary tables and insert the blob into the user application's metadata
                    // tables. This registration happens automatically when SqlRemoteBlob.GetBlobId is called.
                    // Make sure this registration and the application insert is wrapped in the same transaction.
                    //
                    using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
                    {
                        // Enlist the connection into the transaction.
                        //
                        conn.EnlistTransaction(Transaction.Current);

                        // Calling GetBlobId will automatically register the blob.
                        //
                        Console.WriteLine("Created Blob ID: {0}", BitConverter.ToString(blob.GetBlobId()));

                        // Add a new row including the blob ID to the database table.
                        //
                        string addBlobEntry = @" 
                                insert into 
                                    ApplicationSampleTable (SearchTags, BlobId) 
                                values 
                                    ('Sample, RBS, Demo', @blobId);
                            ";

                        using (SqlCommand cmd = new SqlCommand(addBlobEntry, conn))
                        {
                            cmd.Parameters.Add(new SqlParameter("@blobId", blob.GetBlobId()));
                            cmd.ExecuteNonQuery();
                        }
                        Console.WriteLine("Blob ID successfully stored in the application sample table.");
                        ts.Complete();
                    }
                }

                // Success
                //
            }
        }
    }
}
